/*
 * BitMapFreeSpaceManager.h
 *
 *  Created on: Nov 19, 2012
 *      Author: m
 */

#ifndef BITMAP_H_
#define BITMAP_H_

#include <memory>
#include <cstring>
#include "physical_layer_commons.h"
#include "FreeBlocksManager.h"

namespace physical
{

/**
 * Clase BitMap
 *
 * Mapa de bits para administrar espacio libre en archivos de bloques
 */
class BitMapFreeSpaceManager : public FreeBlocksManager
{
protected:

    size_t m_size;  /// Tamaño del BitMap
    std::unique_ptr< byteStream > m_bitmap; /// Array de bits

public:

    /**
     * Constructor de BitMap vacio
     *
     * Crea un bitmap del tamaño especificado, con todos sus
     *  bits en cero.
     *
     * @param size tamaño del mapa en bytes
     */
    BitMapFreeSpaceManager( size_t size );

    /**
     * Constructor por valor
     *
     * @warning Ciudado! el array de bytes pasado como parámetro
     *  debe tener una longitud igual al tamaño del bitmap.
     *  Si el tamaño es mayor solo se copiarán los primeros N
     *  bits al mapa, siendo N el tamaño del mapa.
     *  Si el tamaño es menor el comportamiento no está definido.
     *
     * @param value el contenido a setear en el mapa
     * @param size tamaño del mapa en bytes
     */
    BitMapFreeSpaceManager( size_t size, const byte* value );

    /**
     * Destructor
     */
    ~BitMapFreeSpaceManager();

    /**
     * Marca como Libre el bloque especificado.
     *
     * @param pos Posición del bit a liberar
     */
    void free( blockNumber pos );

    /**
     * Marca como Ocupado el bloque especificado.
     *
     * @param pos Posición del bit a ocupar
     */
    void unfree( blockNumber pos );

    /**
     * Devuelve el número de un bloque libre.
     *
     * @throw NoMoreFreeBlocksException
     *
     * @return Un número de bloque libre
     */
    blockNumber getFreeBlockNumber() const;

    /**
     * Verifica si el bloque especificado está libre o no.
     *
     * @param pos Posición del bit a testear
     * @return true si el bloque esta libre, false en caso contrario
     */
    bool isFree( blockNumber pos ) const;

    /**
     * Devuelve el array de bit asociado
     *
     * @return el array de bits asociado
     */
    const byte* get() const;

    /**
     * Asigna un nuevo valor al mapa de bits
     *
     * @warning Ciudado! el array de bytes pasado como parámetro
     *  debe tener una longitud igual al tamaño del bitmap.
     *  Si el tamaño es mayor solo se copiarán los primeros N
     *  bits al mapa, siendo N el tamaño del mapa.
     *  Si el tamaño es menor el comportamiento no está definido.
     *
     * @param newContent el nuevo contenido a setear en el mapa
     */
    void set( const byte* newContent );

    /**
     * Devuelve el tamaño del mapa de bits en BYTES
     *
     * @return tamaño del mapa en bytes
     */
    size_t getSize() const;

protected:

    /**
     * Devuelve true si el bit bitPos en el byte bytePos está en 1
     *  false en caso contrario
     *
     * @param bitPos Número de bit a testear
     * @param bytePos Posición del byte al que corresponde el bit
     * @return true si el bit está en 1, false en caso contrario
     */
    bool testBit( size_t bitPos, size_t bytePos ) const
    {
        return m_bitmap[bytePos] & ( 0x01 << bitPos );
    }

    /**
     * Setea en 1 el bit dado en el byte correspondiente
     *
     * @param bit Número de bit a setear en 1
     * @param inByte Posición del byte al que corresponde el bit
     */
    void setBit( size_t bitPos, size_t bytePos )
    {
        m_bitmap[bytePos] = m_bitmap[bytePos] | ( 0x01 << bitPos );
    }

    /**
     * Setea en 0 el bit dado en el byte correspondiente
     *
     * @param bit Número de bit a setear en
     * @param inByte Posición del byte al que corresponde el bit
     */
    void unsetBit( size_t bitPos, size_t bytePos )
    {
        m_bitmap[bytePos] = m_bitmap[bytePos] & ~( 0x01 << bitPos );
    }
};

/**
 * Excepción: Excepción Genérica de BitMap
 */
class BitMapException : public PhysicalException
{
};

/**
 * Excepción: No hay más bloques libres en el archivo
 */
class NoMoreFreeBlocksException : public BitMapException
{
    virtual const char* what() const throw()
    {
      return "No more Free Blocks in File.";
    }
};

} /* namespace physical */
#endif /* BITMAP_H_ */
